package com.hmall.trade.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.constants.MqConstants;
import com.hmall.common.domain.MultiDelayMessage;
import com.hmall.common.exception.BadRequestException;
import com.hmall.common.utils.CollUtils;
import com.hmall.common.utils.UserContext;
import com.hmall.api.dto.ItemDTO;
import com.hmall.trade.constants.TradeMqConstants;
import com.hmall.trade.domain.dto.OrderFormDTO;
import com.hmall.trade.domain.po.Order;
import com.hmall.trade.domain.po.OrderDetail;
import com.hmall.trade.mapper.OrderMapper;
import com.hmall.api.client.CartClient;
import com.hmall.api.client.ItemClient;
import com.hmall.trade.service.IOrderDetailService;
import com.hmall.trade.service.IOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final ItemClient itemClient;
    private final IOrderDetailService detailService;
    private final CartClient cartClient;
    private final RabbitTemplate rabbitTemplate;

    @Override
   // @Transactional
    @GlobalTransactional// 开启全局事务,使用分布式事务
    public Long createOrder(OrderFormDTO orderFormDTO) {
        // 1.订单数据
        Order order = new Order();
        // 1.1.查询商品
        List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
        // 1.2.获取商品id和数量的Map
        Map<Long, Integer> itemNumMap = detailDTOS.stream()
                .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));
        Set<Long> itemIds = itemNumMap.keySet();
        // 1.3.查询商品
        List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
        if (items == null || items.size() < itemIds.size()) {
            throw new BadRequestException("商品不存在");
        }
        // 1.4.基于商品价格、购买数量计算商品总价：totalFee
        int total = 0;
        for (ItemDTO item : items) {
            total += item.getPrice() * itemNumMap.get(item.getId());
        }
        order.setTotalFee(total);
        // 1.5.其它属性
        order.setPaymentType(orderFormDTO.getPaymentType());
        order.setUserId(UserContext.getUser());
        order.setStatus(1);
        // 1.6.将Order写入数据库order表中
        save(order);

        // 2.保存订单详情
        List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);
        detailService.saveBatch(details);
        // 3.清理购物车商品
        //cartClient.removeByItemIds(itemIds);
        rabbitTemplate.convertAndSend(MqConstants.TRADE_EXCHANGE_NAME, MqConstants.ROUTING_KEY_ORDER_CREATE, itemIds,
                //在消息发送之前，最后对消息进行处理
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        //将当前登录用户id设置到消息头部中
                        message.getMessageProperties().setHeader("user-info", UserContext.getUser());
                        return message;
                    }
                });

        // 4.扣减库存
        try {
            itemClient.deductStock(detailDTOS);
        } catch (Exception e) {
            throw new RuntimeException("库存不足！");
        }
        try {
            //发送查询订单状态的延迟消息，共延迟了12秒，分别在2s，4s，7s，12s后查询订单状态
            MultiDelayMessage<Long> msg = MultiDelayMessage.of(order.getId(), 2000, 3000, 12000);
            rabbitTemplate.convertAndSend(TradeMqConstants.DELAY_EXCHANGE, TradeMqConstants.DELAY_ORDER_ROUTING_KEY, msg,
                    new MessagePostProcessor() {
                        @Override
                        public Message postProcessMessage(Message message) throws AmqpException {
                            message.getMessageProperties().setDelay(2000);
                            return message;
                        }
                    });
        } catch (AmqpException e) {
            log.error("发送订单支付成功的消息失败"+ e.getMessage());
        }
        return null;
    }

    @Override
    public void markOrderPaySuccess(Long orderId) {
        //查找订单
        Order old = getById(orderId);
        //判断订单状态
        if (old == null || old.getStatus() != 1) {
            //订单不存在或订单状态不为1（待支付）；放弃更新状态
            return;
        }
        //修改订单状态
        Order order = new Order();
        order.setId(orderId);
        order.setStatus(2);
        order.setPayTime(LocalDateTime.now());
        updateById(order);
    }//
    // 即下面的逻辑
    // public void markOrderPaySuccess(Long orderId) {
//        // update `order` set `status` = 2, `pay_time` = now() where `id` = orderId and `status` = 1;
//        lambdaUpdate()
//                .set(Order::getStatus, 2)
//                .set(Order::getPayTime, LocalDateTime.now())
//                .eq(Order::getId, orderId)
//                .eq(Order::getStatus, 1)
//                .update();
//    }

    private List<OrderDetail> buildDetails(Long orderId, List<ItemDTO> items, Map<Long, Integer> numMap) {
        List<OrderDetail> details = new ArrayList<>(items.size());
        for (ItemDTO item : items) {
            OrderDetail detail = new OrderDetail();
            detail.setName(item.getName());
            detail.setSpec(item.getSpec());
            detail.setPrice(item.getPrice());
            detail.setNum(numMap.get(item.getId()));
            detail.setItemId(item.getId());
            detail.setImage(item.getImage());
            detail.setOrderId(orderId);
            details.add(detail);
        }
        return details;
    }
    @Override
    @GlobalTransactional
    public void cancelOrder(Long orderId){
        //1、更新订单的状态为已关闭
        lambdaUpdate()
                .set(Order::getStatus, 5)
                .set(Order::getCloseTime, LocalDateTime.now())
                .eq(Order::getId, orderId)
                .eq(Order::getStatus, 1)
                .update();
        //2、回退商品库存；商品的购买数在订单详情中
        //根据订单id查询订单详情
//        LambdaQueryWrapper<OrderDetail> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(OrderDetail::getOrderId, orderId);
//        List<OrderDetail> list = detailService.list(queryWrapper);
        List<OrderDetail> list = detailService.lambdaQuery().eq(OrderDetail::getOrderId, orderId).list();
        if(CollUtils.isEmpty(list)){
            return;
        }
        List<OrderDetailDTO> orderDetailDTOS = BeanUtil.copyToList(list, OrderDetailDTO.class);
        // 核心SQL： update item_stock set stock = stock - #{num} where item_id = #{itemId}
        // 注意：这里用的是 - #{num}
        for(OrderDetailDTO orderDetailDTO : orderDetailDTOS){
            orderDetailDTO.setNum(orderDetailDTO.getNum() * -1);
        }
        itemClient.deductStock(orderDetailDTOS);
    }
}
